﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Security.Permissions;
using System.Text;
using System.Web;
using System.Web.UI;
using ElectronicCommerce.Framework.Utility;

namespace ElectronicCommerce.Framework.Web.UI.Controls
{

    /// <summary>
    /// A custome control for display breadcrumb
    /// </summary>
    [ToolboxData("<{0}:BreadCrumb runat=server></{0}:BreadCrumb>")]
    [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    public class BreadCrumb : Control
    {
        #region [  Fileds  ]

        private readonly string defaultSeparator = "&nbsp;&raquo;&nbsp;";
        private readonly string hyperLinkHtmlFormat = "<a href=\"{0}\" title=\"{1}\">{2}</a>";

        private string separator;
        private List<BreadCrumbNode> dataSource;

        #endregion

        #region [  Properties  ]

        /// <summary>
        /// Gets or sets the separator.
        /// </summary>
        /// <value>The separator.</value>
        [Browsable(true)]
        [Category("OZZO")]
        [DefaultValue("&nbsp;&raquo;&nbsp;")]
        [Description("Specifies the HTML separating each breadcrumb.")]
        public string Separator
        {
            get
            {
                if (string.IsNullOrEmpty(separator))
                {
                    separator = defaultSeparator;
                }
                return separator;
            }
            set
            {
                separator = value;
            }
        }

        /// <summary>
        /// The data source for this breadcrumb instance
        /// </summary>
        /// <value>The data source.</value>
        [Browsable(false)]
        public List<BreadCrumbNode> DataSource
        {
            get
            {
                return dataSource;
            }
            set
            {
                dataSource = value;
            }
        }

        #endregion

        #region [  Methods  ]

        /// <summary>
        /// Sends server control content to a provided <see cref="T:System.Web.UI.HtmlTextWriter"/> object, which writes the content to be rendered on the client.
        /// </summary>
        /// <param name="writer">The <see cref="T:System.Web.UI.HtmlTextWriter"/> object that receives the server control content.</param>
        protected override void Render(HtmlTextWriter writer)
        {
            if (!DesignMode && dataSource != null && dataSource.Count > 0)
            {
                for (int index = 0; index < dataSource.Count; index++)
                {
                    BreadCrumbNode node = dataSource[index];

                    string html = CreateAnchorHtml(node);
                    writer.Write(html);

                    if (index < dataSource.Count - 1)
                    {
                        writer.Write(Separator);
                    }
                }
            }

            base.Render(writer);
        }

        #endregion

        #region [  Helpers  ]

        /// <summary>
        /// Creat an anchor html from a <see cref="ElectronicCommerce.Framework.Web.UI.Controls.BreadCrumbNode"/>
        /// </summary>
        /// <param name="node"><see cref="ElectronicCommerce.Framework.Web.UI.Controls.BreadCrumbNode"/></param>
        /// <returns></returns>
        protected virtual string CreateAnchorHtml(BreadCrumbNode node)
        {
            if (node == null)
            {
                return string.Empty;
            }

            if (node.IsHyperLink)
            {
                if (node.EncodeMode == EncodeMode.Encode)
                {
                    return string.Format(hyperLinkHtmlFormat
                        , AntiXssEncoder.HtmlAttributeEncode(ResolveUrl(node.NavigateUrl))
                        , AntiXssEncoder.HtmlAttributeEncode(node.Title)
                        , AntiXssEncoder.HtmlEncode(node.InnerText)
                    );
                }
                else if (node.EncodeMode == EncodeMode.NotEncode)
                {
                    return string.Format(hyperLinkHtmlFormat
                          , ResolveUrl(node.NavigateUrl)
                          , node.Title
                          , node.InnerText
                      );
                }
            }
            else
            {
                if (node.EncodeMode == EncodeMode.Encode)
                {
                    return AntiXssEncoder.HtmlEncode(node.InnerText);
                }
                else if (node.EncodeMode == EncodeMode.NotEncode)
                {
                    return node.InnerText;
                }
            }

            return string.Empty;
        }

        #endregion
    }

    /// <summary>
    /// A custome class for breadcrumb node
    /// </summary>
    public class BreadCrumbNode
    {
        #region [  Fields  ]

        private string innerText;
        private string title;
        private string navigateUrl;
        private EncodeMode encodeMode = EncodeMode.Encode;

        #endregion

        #region [  Constructors  ]

        /// <summary>
        /// Initializes a new instance of the <see cref="BreadCrumbNode"/> class.
        /// </summary>
        private BreadCrumbNode() { }
        /// <summary>
        /// Initializes a new instance of the <see cref="BreadCrumbNode"/> class.
        /// </summary>
        /// <param name="innerText">The inner text.</param>
        public BreadCrumbNode(string innerText)
            : this(innerText, string.Empty)
        {
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="BreadCrumbNode"/> class.
        /// </summary>
        /// <param name="innerText">The inner text.</param>
        /// <param name="title">The title.</param>
        public BreadCrumbNode(string innerText, string title)
            : this(innerText, title, string.Empty)
        {

        }
        /// <summary>
        /// Initializes a new instance of the <see cref="BreadCrumbNode"/> class.
        /// </summary>
        /// <param name="innerText">The inner text.</param>
        /// <param name="title">The title.</param>
        /// <param name="navigateUrl">The navigate URL.</param>
        public BreadCrumbNode(string innerText, string title, string navigateUrl)
            : this(innerText, title, navigateUrl, EncodeMode.Encode)
        {
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="BreadCrumbNode"/> class.
        /// </summary>
        /// <param name="innerText">The inner text.</param>
        /// <param name="title">The title.</param>
        /// <param name="navigateUrl">The navigate URL.</param>
        /// <param name="encodeMode">The encode mode.</param>
        public BreadCrumbNode(string innerText, string title, string navigateUrl, EncodeMode encodeMode)
        {
            this.innerText = innerText;
            this.title = title;
            this.navigateUrl = navigateUrl;
            this.encodeMode = encodeMode;
        }

        #endregion

        #region [  Properties  ]

        /// <summary>
        /// Get if the node is a hyperlink
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is hyper link; otherwise, <c>false</c>.
        /// </value>
        internal bool IsHyperLink
        {
            get
            {
                if (navigateUrl != null)
                {
                    return (navigateUrl.Trim().Length > 0);
                }
                return false;
            }
        }

        /// <summary>
        /// Get the node's inner html
        /// </summary>
        /// <value>The inner text.</value>
        public string InnerText
        {
            get
            {
                return innerText;
            }
        }

        /// <summary>
        /// Get the node's title
        /// </summary>
        /// <value>The title.</value>
        public string Title
        {
            get
            {
                return title;
            }
        }

        /// <summary>
        /// Get the node's navigate url address
        /// </summary>
        /// <value>The navigate URL.</value>
        public string NavigateUrl
        {
            get
            {
                return navigateUrl;
            }
        }

        /// <summary>
        /// Specifies the <see cref="ElectronicCommerce.Framework.Web.UI.Controls.BreadCrumbNode"/>'s
        /// <see cref="ElectronicCommerce.Framework.Web.UI.Controls.EncodeMode"/>
        /// </summary>
        /// <value>The encode mode.</value>
        public EncodeMode EncodeMode
        {
            get
            {
                return encodeMode;
            }
            set
            {
                encodeMode = value;
            }
        }

        #endregion
    }

    /// <summary>
    /// Specifies the <see cref="ElectronicCommerce.Framework.Web.UI.Controls.BreadCrumbNode"/>'s Encode mode
    /// </summary>
    public enum EncodeMode
    {
        NotEncode,
        Encode
    }
}
